home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / processes / procdoggie / umenuhandler.p < prev    next >
Encoding:
Text File  |  2000-09-28  |  14.6 KB  |  454 lines

  1. {
  2.     File:        UMenuHandler.p
  3.  
  4.     Contains:    All of the code in this module is used to maintain the menus and to handle
  5.                 menu selections by the user.
  6.  
  7.     Written by: Forrest Tanaka    
  8.  
  9.     Copyright:    Copyright © 1988-1999 by Apple Computer, Inc., All Rights Reserved.
  10.  
  11.                 You may incorporate this Apple sample source code into your program(s) without
  12.                 restriction. This Apple sample source code has been provided "AS IS" and the
  13.                 responsibility for its operation is yours. You are not permitted to redistribute
  14.                 this Apple sample source code as "Apple sample source code" after having made
  15.                 changes. If you're going to re-distribute the source, we require that you make
  16.                 it clear in the source that the code was descended from Apple sample source
  17.                 code, but that you've made changes.
  18.  
  19.     Change History (most recent first):
  20.                 7/27/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  21.                 
  22.  
  23. }
  24. UNIT UMenuHandler;
  25.  
  26. {[j=20/57/1$] Pasmat Options}
  27.  
  28.  
  29. INTERFACE
  30.  
  31.  
  32. (*******************************************************************************
  33. * Used Units
  34. *******************************************************************************)
  35.  
  36.     USES
  37.         (* Application *)
  38.         UGlobals
  39.         ,UProcessUtils
  40.         ,UProcessGuts
  41.         ;
  42.  
  43.  
  44. (*******************************************************************************
  45. * Constants
  46. *******************************************************************************)
  47.  
  48.     CONST
  49.         mApple = 128; {Menu ID and resource ID of Apple menu}
  50.         iAbout = 1;   {Menu item number of About SevenPaint item}
  51.  
  52.         mFile        = 129; {Menu ID and resource ID of File menu}
  53.         iClose         = 1;    {Menu item number of Close item}
  54.         iLaunchFore  = 3;   {Menu item number of Launch to Foreground… item}
  55.         iLaunchBack  = 4;   {Menu item number of Launch to Background… item}
  56.         iLaunchTo    = 5;   {Menu item number of Launch To… item}
  57.         iJustLaunch  = 7;   {Menu item number of Simple Launch item}
  58.         iOpenLaunch  = 8;   {Menu item number of Open Documents on Launch item}
  59.         iPrintLaunch = 9;   {Menu item number of Print Documents on Launch item}
  60.         iQuit        = 11;  {Menu item number of Quit item}
  61.  
  62.         mProcess          = 130; {Menu ID and resource ID of Process menu}
  63.         iBringFront       = 1;   {Menu item number of Bring Process to Front item}
  64.         iShowProcessInfo  = 2;   {Menu item number of Show Process Info item}
  65.         iTerminateProcess = 3;   {Menu item number of Terminate Process item}
  66.  
  67.  
  68. (*******************************************************************************
  69. * StartMenus - Do additional initialization of the menus
  70. *
  71. * This routine is called just after calling the Utilities sample code routine,
  72. * StandardMenuSetup.  This application needs to do just a little bit of
  73. * additional initialization for menus.  See below for details.
  74. *
  75. * If there isn’t enough memory to load the menus, then the gError global is set
  76. * to memFullErr.  If desired menu resources couldn’t be found, then gError is
  77. * set to resNotFound.  If any other error occurs, then gError is set to
  78. * dsSysErr.
  79. *******************************************************************************)
  80.  
  81.     PROCEDURE StartMenus;
  82.  
  83.  
  84. (*******************************************************************************
  85. * DoMenuChoice - Dispatch to the appropriate routine for a menu choice
  86. *
  87. * When it’s determined that a menu item was chosen, this routine is called to
  88. * dispatch to the appropriate routine for the chosen menu item.  The menu item
  89. * and menu number returned by MenuSelect and MenuKey is passed in the menuChoice
  90. * parameter.
  91. *******************************************************************************)
  92.  
  93.     PROCEDURE DoMenuChoice (menuChoice: LongInt);
  94.  
  95.  
  96. (*******************************************************************************
  97. * FixMenus - Fix menus so that proper items are enabled and marked
  98. *
  99. * FixMenus is called to assure that menu items are disable, enabled, marked, and
  100. * unmarked appropriately.  It’s called at the end of every iteration of the main
  101. * event loop.
  102. *******************************************************************************)
  103.  
  104.     PROCEDURE FixMenus;
  105.  
  106.  
  107. IMPLEMENTATION
  108.  
  109.     USES
  110.         Resources
  111.         ,Devices
  112.         ,ToolUtils
  113.         ;
  114.         
  115. (*******************************************************************************
  116. * Constants
  117. *******************************************************************************)
  118.  
  119.     CONST
  120.         rMenuBar = 128; {Resource ID of this application’s MBAR resource}
  121.  
  122.         mFirst = mFile;    {Menu ID of the first non-Apple menu in the menu list}
  123.         mLast  = mProcess; {Menu ID of the last menu in the menu list}
  124.  
  125.  
  126. (*******************************************************************************
  127. * Types
  128. *******************************************************************************)
  129.  
  130.     TYPE
  131.         MenuGuide = RECORD
  132.             theMenu: MenuHandle; {Handle to this guide’s menu}
  133.             enables: LongInt     {Current enable flags}
  134.         END;
  135.  
  136.  
  137. (*******************************************************************************
  138. * Variables
  139. *******************************************************************************)
  140.  
  141.     VAR
  142.         gMenuGuides: ARRAY [mFirst..mLast] OF MenuGuide;
  143.  
  144. {$S Startup}
  145. (*******************************************************************************
  146. * Public: StartMenus
  147. *
  148. * The menu guide array is initialized with the menu handles and enable flags of
  149. * all menus.
  150. *
  151. * If GetNewMBar couldn’t load the MBAR resource, then it returns NIL and the
  152. * error code is in ResError, and I can deal with the error elegantly.  But, if
  153. * the GetNewMBar couldn’t load the menus themselves, then it’ll probably crash.
  154. *******************************************************************************)
  155.  
  156.     PROCEDURE StartMenus;
  157.  
  158.         VAR
  159.             menuBar:   Handle;  {Handle to the menu bar from the MBAR resource}
  160.             menuIndex: Integer; {Index into menu guide records}
  161.  
  162.     BEGIN
  163.         (* Load in the menu bar *)
  164.         menuBar := GetNewMBar (rMenuBar);
  165.         IF menuBar <> NIL THEN
  166.             BEGIN
  167.                 (* Set it, then dispose of it because SetMenuBar makes a copy *)
  168.                 SetMenuBar (menuBar);
  169.                 DisposeHandle (menuBar);
  170.  
  171.                 (* Add the desk accessories to the Apple menu *)
  172.                 AppendResMenu (GetMenuHandle (mApple), 'DRVR');
  173.  
  174.                 (* Initialize the menu guide array *)
  175.                 FOR menuIndex := mFile TO mProcess DO
  176.                     BEGIN
  177.                         gMenuGuides [menuIndex].theMenu := GetMenuHandle (menuIndex);
  178.                         gMenuGuides [menuIndex].enables := gMenuGuides [menuIndex].
  179.                                 theMenu^^.enableFlags
  180.                     END;
  181.  
  182.                 (* Draw the menu bar *)
  183.                 DrawMenuBar
  184.             END
  185.         ELSE
  186.             IF ResError = memFullErr THEN
  187.                 gError := memFullErr
  188.             ELSE IF (ResError = noErr) OR (ResError = resNotFound) THEN
  189.                 gError := resNotFound
  190.             ELSE
  191.                 gError := dsSysErr
  192.     END;
  193.  
  194.  
  195. {$S Main}
  196. (*******************************************************************************
  197. * Private: DoAppleMenu - Handle an Apple menu item choice
  198. *
  199. * This routine is called whenever it’s determined that the chosen menu item was
  200. * in the Apple menu.  If the chosen menu item that’s passed in the menuItem
  201. * parameter wasn’t the About item, the name of the menu item is retrieved and
  202. * then OpenDeskAcc is called with this name so that the desk accessory by that
  203. * name is opened.  The Process Manager can launch desk accessories, but
  204. * OpenDeskAcc should still be used if the user chooses any item in the Apple
  205. * menu.
  206. *******************************************************************************)
  207.  
  208.     PROCEDURE DoAppleMenu (menuItem: Integer);
  209.  
  210.         VAR
  211.             daName: Str255;  {Name of the chosen DA}
  212.             refNum: Integer; {Reference number of the DA, ignored}
  213.  
  214.     BEGIN
  215.         IF menuItem = iAbout THEN
  216.             ShowAboutBox
  217.         ELSE
  218.             BEGIN
  219.                 GetMenuItemText (GetMenuHandle (mApple), menuItem, (*<*)daName);
  220.                 refNum := OpenDeskAcc (daName)
  221.             END
  222.     END;
  223.  
  224.  
  225. {$S Main}
  226. (*******************************************************************************
  227. * Private: DoFileMenu - Handle a File menu item choice
  228. *
  229. * This routine is called whenever it’s determined that the chosen menu item was
  230. * in the File menu.  The item number of the chosen menu item is passed in the
  231. * menuItem parameter.
  232. *******************************************************************************)
  233.  
  234.     PROCEDURE DoFileMenu (menuItem: Integer);
  235.  
  236.         VAR
  237.             junkError: OSErr;
  238.             
  239.     BEGIN
  240.         CASE menuItem OF
  241.             iClose:
  242.                 DoWindowClose(FrontWindow);
  243.             iLaunchFore:
  244.                 DoLaunchInFront;
  245.             iLaunchBack:
  246.                 DoLaunchInBack;
  247.             iLaunchTo:
  248.                 DoLaunchTo;
  249.             iJustLaunch,
  250.             iOpenLaunch,
  251.             iPrintLaunch:
  252.                 DoLaunchMode (menuItem);
  253.             iQuit:
  254.                 junkError := DoQuit
  255.         END
  256.     END;
  257.  
  258.  
  259. {$S Main}
  260. (*******************************************************************************
  261. * Private: DoProcessMenu - Handle a Process menu item choice
  262. *
  263. * This routine is called whenever it’s determined that the chosen menu item was
  264. * in the Process menu.  The item number of the chosen menu item is passed in the
  265. * menuItem parameter.
  266. *******************************************************************************)
  267.  
  268.     PROCEDURE DoProcessMenu (menuItem: Integer);
  269.  
  270.     BEGIN
  271.         CASE menuItem OF
  272.             iBringFront:
  273.                 DoBringProcessToFront (FrontWindow);
  274.             iShowProcessInfo:
  275.                 DoGetProcessInfo (FrontWindow);
  276.             iTerminateProcess:
  277.                 DoTerminateProcess (FrontWindow)
  278.         END
  279.     END;
  280.  
  281.  
  282. {$S Main}
  283. (*******************************************************************************
  284. * Public: DoMenuChoice
  285. *
  286. * This routine should be self-explanatory.
  287. *******************************************************************************)
  288.  
  289.     PROCEDURE DoMenuChoice (menuChoice: LongInt);
  290.  
  291.         VAR
  292.             menuNum:     Integer; {Menu number of chosen menu}
  293.             menuItem:    Integer; {Item number of chosen menu item}
  294.             startTicks: longint; {TickCount when menu command started}
  295.     BEGIN
  296.         IF menuChoice <> 0 THEN
  297.             BEGIN
  298.                 startTicks := TickCount;
  299.                 
  300.                 (* Get the chosen menu item and menu number *)
  301.                 menuNum := HiWord (menuChoice);
  302.                 menuItem := LoWord (menuChoice);
  303.  
  304.                 (* Dispatch the appropriate menu-handling routine *)
  305.                 CASE menuNum OF
  306.                     mApple:
  307.                         DoAppleMenu (menuItem);
  308.                     mFile:
  309.                         DoFileMenu (menuItem);
  310.                     mProcess:
  311.                         DoProcessMenu (menuItem);
  312.                 END;
  313.                 
  314.                 WHILE TickCount < (startTicks + 6) DO BEGIN
  315.                     (* Wait to make sure menu highlighting is visible. *)
  316.                 END;
  317.                 
  318.                 IF NOT gQuitting THEN BEGIN
  319.                     HiliteMenu (0);
  320.                 END;
  321.             END
  322.     END;
  323.  
  324.  
  325. {$S Main}
  326. (*******************************************************************************
  327. * Private: ResetMenuItems - Disable any disableable items and clear marks
  328. *
  329. * Disabling all the menu items is done bruteforcedly.  It could easily be done
  330. * by looping through each menu and disabling every item that comes up (disabling
  331. * a Font menu would be done this way), but I thought doing it using the brute-force
  332. * method was clearer.  Then again. . .
  333. *******************************************************************************)
  334.  
  335.     PROCEDURE ResetMenuItems;
  336.  
  337.         VAR
  338.             aMenu: MenuHandle; {Handle to each menu we’re disabling}
  339.  
  340.     BEGIN
  341.         (* Disable items in the File menu *)
  342.         aMenu := GetMenuHandle (mFile);
  343.         DisableItem (aMenu, iClose);
  344.         DisableItem (aMenu, iLaunchFore);
  345.         DisableItem (aMenu, iLaunchBack);
  346.         DisableItem (aMenu, iLaunchTo);
  347.         SetItemMark (aMenu, iJustLaunch, CHR (noMark));
  348.         SetItemMark (aMenu, iOpenLaunch, CHR (noMark));
  349.         SetItemMark (aMenu, iPrintLaunch, CHR (noMark));
  350.  
  351.         (* Disable items in the Process menu *)
  352.         aMenu := GetMenuHandle (mProcess);
  353.         DisableItem (aMenu, iBringFront);
  354.         DisableItem (aMenu, iShowProcessInfo);
  355.         DisableItem (aMenu, iTerminateProcess);
  356.     END;
  357.  
  358.  
  359. {$S Main}
  360. (*******************************************************************************
  361. * Public: FixMenus
  362. *
  363. * FixMenus first disables every available menu item.  Then the most basic menu
  364. * items are enabled.  The windowKind field of the front window is then checked.
  365. * If there is a window open, FixMenus calls a routine that’s responsible for
  366. * that kind of window to enable any menu items that are relevant to that kind of
  367. * window.
  368. *
  369. * After this is done, the menu bar might have to be redrawn to reflect the new
  370. * conditions.  So, FixMenus go through every menu to determine if the state of
  371. * the entire menu has changed.  The MenuGuide records are used to help determine
  372. * this.  If the state of any many has changed, then the menu bar is redrawn.
  373. *******************************************************************************)
  374.  
  375.     PROCEDURE FixMenus;
  376.  
  377.         VAR
  378.             currWindow: WindowPtr;  {Pointer to the front-most window}
  379.             currMenu:   MenuHandle; {Handle to menu being enabled}
  380.             oldEnables: LongInt;    {True if 1+ menu items enabled when FixMenus called}
  381.             newEnables: LongInt;    {True if 1+ menu items enabled after menus fixed}
  382.             mustRedraw: Boolean;    {TRUE if menu bar has to be redrawn}
  383.             numItems:   Integer;    {Number of items in a menu}
  384.             menuIndex:  Integer;    {Index into menu guide array}
  385.  
  386.     BEGIN
  387.         (* Start by disabling all menus *)
  388.         ResetMenuItems;
  389.  
  390.         (* Front-most window determines most menu enabling/disabling *)
  391.         currWindow := FrontWindow;
  392.  
  393.         (* Fix the marks for the launch mode items *)
  394.         currMenu := GetMenuHandle (mFile);
  395.         CASE GetLaunchMode OF
  396.             kJustLaunch:
  397.                 CheckItem (currMenu, iJustLaunch, TRUE);
  398.             kOpenLaunch:
  399.                 CheckItem (currMenu, iOpenLaunch, TRUE);
  400.             kPrintLaunch:
  401.                 CheckItem (currMenu, iPrintLaunch, TRUE)
  402.         END;
  403.  
  404.         (* Enable any window-specific menu items *)
  405.         IF currWindow <> NIL THEN
  406.             IF IsProcessListWindow (currWindow) THEN
  407.                 (* Process list window in front, set up menu items in it *)
  408.                 FixProcessListMenus (currWindow)
  409.             ELSE IF IsProcessInfoWindow (currWindow) THEN
  410.                 (* Process info window in front, set up menu items in it *)
  411.                 FixProcessInfoMenus (currWindow);
  412.  
  413.         (* Assume we don’t have to redraw the menu bar *)
  414.         mustRedraw := FALSE;
  415.  
  416.         (* Check through every menu to see if there are any enabled items in it *)
  417.         FOR menuIndex := mFirst TO mLast DO
  418.             BEGIN
  419.                 (* Grab the old and new enable flags excluding the flag for the entire menu *)
  420.                 oldEnables := BAnd (gMenuGuides [menuIndex].enables, $FFFFFFFE);
  421.                 newEnables := BAnd (gMenuGuides [menuIndex].theMenu^^.enableFlags,
  422.                         $FFFFFFFE);
  423.  
  424.                 (* Shift left so that we only see flags for existing items *)
  425.                 numItems := CountMItems (gMenuGuides [menuIndex].theMenu);
  426.                 oldEnables := BitShift (oldEnables, 31 - numItems);
  427.                 newEnables := BitShift (newEnables, 31 - numItems);
  428.  
  429.                 (* Determine if the menu bar must be redrawn *)
  430.                 IF (oldEnables <> 0) AND (newEnables = 0) THEN
  431.                     BEGIN
  432.                         (* Had some items enabled, now has no items enabled, redraw *)
  433.                         DisableItem (gMenuGuides [menuIndex].theMenu, 0);
  434.                         mustRedraw := TRUE
  435.                     END
  436.                 ELSE IF (oldEnables = 0) AND (newEnables <> 0) THEN
  437.                     BEGIN
  438.                         (* Had no items enabled, now has some items enabled, redraw *)
  439.                         EnableItem (gMenuGuides [menuIndex].theMenu, 0);
  440.                         mustRedraw := TRUE
  441.                     END;
  442.  
  443.                 (* Update our copy of the enable flags *)
  444.                 gMenuGuides [menuIndex].enables := gMenuGuides [menuIndex].
  445.                         theMenu^^.enableFlags
  446.             END;
  447.  
  448.         (* If at least one menu has changed state, must redraw the menu bar *)
  449.         IF mustRedraw THEN
  450.             InvalMenuBar
  451.     END;
  452.  
  453. END.
  454.